﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using PreProcessingLanguage;

namespace CGeers.Wcf.Services.Preprocesslanguage
{
    public class Ngram
    {
        public static bool allowDelCount = true;
        public static int countDel = 5;
        private bool allowDelValue = false;
        private double thresholdDel = 0.2;
        private static bool isReaded = false;

        public static Dictionary<string, Dictionary<string, double>> P1 = new Dictionary<string, Dictionary<string, double>>();
        public static Dictionary<string, Dictionary<string, double>> P2 = new Dictionary<string, Dictionary<string, double>>();
        public static Dictionary<string, Dictionary<string, double>> P3 = new Dictionary<string, Dictionary<string, double>>();

        public bool AllowDelValue { get { return allowDelValue; } set { allowDelValue=value;} }
        public double ThresholdDel { get { return thresholdDel; } set { thresholdDel = value; } }
        public bool AllowDelCount { get { return allowDelCount; } set { allowDelCount=value;} }
        public int CountDel { get { return countDel; } set { countDel=value;} }


        public Dictionary<string, double> process(string input)
        {
            try
            {
                Dictionary<string, double> kq = new Dictionary<string, double>();
                string[] wordsUS = input.Split(' ');            //chia thành mảng từ không dấu
                Dictionary<string, double> words;               //danh sách từ có dấu từ 1 từ không dấu
                Dictionary<string, double> listWords;            //danh sách các câu có thể tạo thành từ từ ko dấu
                Dictionary<string, double> temp;                //danh sách tạm
                List<string> temp_word = new List<string>();
                bool isFirst = true;


                if (P1.ContainsKey(wordsUS[0]))
                    words = P1[wordsUS[0]];
                else
                {
                    words = new Dictionary<string, double>();
                    words.Add(wordsUS[0], 1.0);
                }
                kq = words;
                temp_word.Add(wordsUS[0]);

                if (wordsUS.Length >= 2)
                {
                    if (P1.ContainsKey(wordsUS[1]))
                        words = P1[wordsUS[1]];
                    else
                    {
                        words = new Dictionary<string, double>();
                        words.Add(wordsUS[1], 1.0);
                    }
                    temp_word.Add(wordsUS[1]);
                    listWords = new Dictionary<string, double>();
                    foreach (KeyValuePair<string, double> pair in kq)
                    {
                        foreach (KeyValuePair<string, double> w in words)
                        {
                            if (allowDelValue)
                            {
                                if (pair.Value > thresholdDel)
                                {
                                    listWords.Add(pair.Key + " " + w.Key, pair.Value);
                                }
                            }
                            else
                            {
                                listWords.Add(pair.Key + " " + w.Key, pair.Value);
                            }
                        }
                    }
                    temp = new Dictionary<string, double>();

                    foreach (KeyValuePair<string, double> s in listWords)
                    {
                        if (P2.ContainsKey(PreProcessing.ConvertToUnSign(s.Key)))
                        {
                            if (P2[PreProcessing.ConvertToUnSign(s.Key)].ContainsKey(s.Key))
                            {
                                temp.Add(s.Key, s.Value * P2[PreProcessing.ConvertToUnSign(s.Key)][s.Key]*1.0);
                            }
                            else
                            {
                                temp.Add(s.Key, s.Value/100);
                            }
                        }
                        else
                        {
                            temp.Add(s.Key, s.Value/100);
                        }
                    }
                    if (allowDelCount)
                        kq = getKqForCount(temp, countDel);
                    else
                        kq = temp;

                    for (int i = 2; i < wordsUS.Length; i++)
                    {
                        if (P1.ContainsKey(wordsUS[i]))
                            words = P1[wordsUS[i]];
                        else
                        {
                            words = new Dictionary<string, double>();
                            words.Add(wordsUS[i], 1.0);
                        }
                        temp_word.Add(wordsUS[i]);
                        if (isFirst == false)
                        {
                            temp_word.RemoveAt(0);
                        }
                        isFirst = false;
                        listWords = new Dictionary<string, double>();
                        foreach (KeyValuePair<string, double> pair in kq)
                        {
                            foreach (KeyValuePair<string, double> w in words)
                            {
                                if (allowDelValue)
                                {
                                    if (pair.Value > thresholdDel)
                                    {
                                        listWords.Add(pair.Key + " " + w.Key, pair.Value*1.0);
                                    }
                                }
                                else
                                {
                                    listWords.Add(pair.Key + " " + w.Key, pair.Value*1.0);
                                }
                            }
                        }
                        temp = new Dictionary<string, double>();
                        foreach (KeyValuePair<string, double> s in listWords)
                        {
                            if (P3.ContainsKey(temp_word[0] + " " + temp_word[1] + " " + temp_word[2]))
                            {
                                string[] str = s.Key.Split(' ');
                                if (P3[temp_word[0] + " " + temp_word[1] + " " + temp_word[2]].ContainsKey(str[str.Length - 3] + " " + str[str.Length - 2] + " "+str[str.Length-1]))
                                {
                                    temp.Add(s.Key, s.Value * P3[temp_word[0] + " " + temp_word[1] + " " + temp_word[2]][str[str.Length - 3] + " " + str[str.Length - 2] + " "+str[str.Length-1]]*1.0);
                                }
                                else
                                {
                                    temp.Add(s.Key, s.Value/100);
                                }
                            }
                            else
                            {
                                temp.Add(s.Key, s.Value/100);
                            }
                        }
                        if (allowDelCount)
                            kq = getKqForCount(temp, countDel);
                        else
                            kq = temp;
                    }
                }
                return kq;
            }
            catch (Exception e)
            {
                Console.WriteLine("Lỗi:" + e.StackTrace);
            }
            return null;
        }
        public string getKq(Dictionary<string, double> kq)
        {
            try
            {
                double max = kq.Max(kvp => kvp.Value);
                return kq.Where(kvp => kvp.Value == max).Select(kvp => kvp.Key).First();
            }
            catch (Exception)
            {
                return null;
            }
        }
        public static bool readData(string path1, string path2, string path3)
        {
            
            try
            {
                if (isReaded == false)
                {
                    isReaded = true;
                    Console.WriteLine("Preparing to start service!");
                    Console.WriteLine("Reading data...");
                    StreamReader sr = new StreamReader(path1);
                    Dictionary<string, double> pp;
                    string str;
                    while ((str = sr.ReadLine()) != null)
                    {
                        string[] ppp = str.Split(':');
                        string[] pppp = ppp[1].Split(';');
                        pp = new Dictionary<string, double>();
                        foreach (string s in pppp)
                        {
                            string[] ppppp = s.Split('-');
                            pp.Add(ppppp[0], double.Parse(ppppp[1]));
                        }
                        P1.Add(ppp[0], pp);
                    }
                    sr.Close();
                    sr = new StreamReader(path2);
                    while ((str = sr.ReadLine()) != null)
                    {
                        string[] ppp = str.Split(':');
                        string[] pppp = ppp[1].Split(';');
                        pp = new Dictionary<string, double>();
                        foreach (string s in pppp)
                        {
                            string[] ppppp = s.Split('-');
                            pp.Add(ppppp[0], double.Parse(ppppp[1]));
                        }
                        P2.Add(ppp[0], pp);
                    }
                    sr.Close();
                    sr = new StreamReader(path3);
                    while ((str = sr.ReadLine()) != null)
                    {
                        string[] ppp = str.Split(':');
                        string[] pppp = ppp[1].Split(';');
                        pp = new Dictionary<string, double>();
                        foreach (string s in pppp)
                        {
                            string[] ppppp = s.Split('-');
                            pp.Add(ppppp[0], double.Parse(ppppp[1]));
                        }
                        P3.Add(ppp[0], pp);
                    }
                    sr.Close();
                    Console.WriteLine("Completed");
                }
                    return true;
            }
            catch (Exception)
            {
                return false;
            }

        }
        public Dictionary<string,double> getKqForCount(Dictionary<string, double> dict, int count)
        {
            var items = from pair in dict
                        orderby pair.Value descending
                        select pair;
            Dictionary<string, double> kq = new Dictionary<string, double>();
            foreach (KeyValuePair<string, double> pair in items)
            {
                if (count == 0)
                    return kq;
                count--;
                kq.Add(pair.Key, pair.Value);
            }
            return kq;
        }
        public static string sortList(Dictionary<string, double> dict, int lines)
        {
            var items = from pair in dict
                        orderby pair.Value descending
                        select pair;
            string rs = "";
            int count = 0;
            foreach (KeyValuePair<string, double> pair in items)
            {
                if (count >= lines) return rs;
                rs += pair.Key + "\t\t" + pair.Value + "\n";
                count++;
            }
            return rs;
        }
    }
}
